# coding = gbk

import bpy
import bmesh
import struct
import mathutils
import math
import ctypes

from bpy_extras.io_utils import (ImportHelper,
							ExportHelper,
							path_reference_mode,
							axis_conversion,
							)

from bpy.props import BoolProperty
from bpy.props import EnumProperty
from bpy.props import StringProperty


from bpy.types import Panel, Menu
from rna_prop_ui import PropertyPanel
from bpy.props import *

EXPORT_APPLY_MODIFIERS_RENDER = True

ENUM_树干 = 1
ENUM_树叶 = 2
ENUM_树骨骼 = 3


#保存对象名称
def f_SaveObjName(file, name):
	#保存文本数量
	strName = bytes(name, encoding = 'gbk')
	file.write( struct.pack('<I', len(strName)) )
	for i in range(len(strName)):
		file.write( struct.pack('B', strName[i]) )

def f_是否为树对象(obj, 树元素类型):
	if len(obj.game.sensors) > 0 :
			for t in obj.game.sensors:
				if t.name == 树元素类型 and t.type == 'MESSAGE' :
					return True
	return False


class C_OBJECT_设置为植被属性(bpy.types.Operator):	
	bl_idname = "object.trunk"
	bl_label = "设置为树干"

	def invoke(self, context, event):
		是否设置为树类型 = True

		obj = context.object
		if len(obj.game.sensors) > 0 :
			for t in obj.game.sensors:
				if t.name == "T_TreeTrunk" and t.type == 'MESSAGE' :
					是否设置为树类型 = False

		if 是否设置为树类型 :
			bpy.ops.logic.sensor_add(type='MESSAGE', name='T_TreeTrunk')
		return {'CANCELLED'}

class C_OBJECT_设置为树叶属性(bpy.types.Operator):	
	bl_idname = "object.tree_leaves"
	bl_label = "设置为树叶"

	def invoke(self, context, event):
		是否设置为树类型 = True

		obj = context.object
		if len(obj.game.sensors) > 0 :
			for t in obj.game.sensors:
				if t.name == "T_TreeLeaves" and t.type == 'MESSAGE' :
					是否设置为树类型 = False

		if 是否设置为树类型 :
			bpy.ops.logic.sensor_add(type='MESSAGE', name='T_TreeLeaves')
		return {'CANCELLED'}

class C_OBJECT_设置为植被骨骼(bpy.types.Operator):	
	bl_idname = "object.tree_bone"
	bl_label = "设置为树"

	def invoke(self, context, event):
		是否设置为树骨骼类型 = True

		obj = context.object
		if len(obj.game.sensors) > 0 :
			for t in obj.game.sensors:
				if t.name == "T_TreeBone" and t.type == 'MESSAGE' :
					是否设置为树骨骼类型 = False

		if 是否设置为树骨骼类型 :
			bpy.ops.logic.sensor_add(type='MESSAGE', name='T_TreeBone')
			
		return {'CANCELLED'}






class ObjectButtonsPanel:
	bl_space_type = 'PROPERTIES'
	bl_region_type = 'WINDOW'
	bl_context = "object"

class OBJECT_PT_植被(ObjectButtonsPanel, Panel):
	bl_label = "植被属性"
	#bpy.props.BoolProperty(name='是否树')
	def draw(self, context):
		layout = self.layout
		obj = context.object
		if f_是否为树对象(obj, 'T_TreeTrunk') :
			layout.label(text="树干类型")
			树干分支 = "分支: "
			for 分支 in obj.lod_levels:
				树干分支 += 分支.object.name + " / "
			layout.label(text=树干分支)

		elif f_是否为树对象(obj, 'T_TreeLeaves') :
			layout.label(text="树叶类型")
			树叶分支 = "分支树叶: "
			for 树叶 in obj.lod_levels:
				树叶分支 += 树叶.object.name + " / "
			layout.label(text=树叶分支)

		elif f_是否为树对象(obj, 'T_TreeBone') :
			layout.label(text="树骨骼类型")
			骨骼分支 = "分支骨骼: "
			for 骨骼 in obj.lod_levels:
				骨骼分支 += 骨骼.object.name + " / "
			layout.label(text=骨骼分支)

		layout.operator("object.trunk")
		layout.operator("object.tree_leaves")
		layout.operator("object.tree_bone")
		#split = layout.split()


def f_保存网格物体(binFile, obj, scene):
	me = obj.to_mesh(scene, True, calc_tessface=False, settings='RENDER' if EXPORT_APPLY_MODIFIERS_RENDER else 'PREVIEW')
	bm = bmesh.new()
	bm.from_mesh(me)

	#bmesh.ops.triangulate(bm, faces=bm.faces)
	bmesh.ops.rotate(bm, verts=bm.verts[:], cent=(1.0, 0.0, 0.0), matrix=mathutils.Matrix.Rotation(math.radians(-90.0), 3, 'X'))
	bmesh.ops.scale(bm, vec=mathutils.Vector((1.0, 1.0, 1.0)), space=mathutils.Matrix.Scale(1, 4, (1.0, 1.0, 1.0)), verts=bm.verts[:])
	
	bm.to_mesh(me)
	bm.free()

	#数据组 ---------------------------------------- 网格数据拷贝到缓存里 -------------------------------------------
	UVCoord = []
	Normal = []
	Vertex = []
	VIndex = []
	#VWeight = []

	#记录顶点和法线 分配uv空间
	for vert in me.vertices:
		for v in vert.co:
			Vertex.append(v)
		for n in vert.normal:
			Normal.append(n)
		UVCoord.append(0.0)
		UVCoord.append(0.0)	

	UVlayerID = 0
	for face in me.polygons:
		for ri in range(0, 3):
			i = face.vertices[ri]
			VIndex.append(struct.pack('<I', i))

			if len(me.uv_layers):
				ti = face.loop_indices[ri]
				uv = me.uv_layers[0].data[ti].uv
				UVCoord[i*2]	= uv[0]
				UVCoord[i*2+1]	= uv[1]

	
	'''----------------------------------------  网格写出  -------------------------------------------'''
	#保存定点数量
	binFile.write( struct.pack('<I', len(Vertex)) )
	#保存定点
	for vert in Vertex:
		s = struct.pack('<f', vert)
		binFile.write( s )
	print("顶点数量", len(Vertex))
	#保存法线数量
	binFile.write( struct.pack('<I', len(Normal)) )
	print("Normal", len(Normal))
	#保存法线
	for normal in Normal:
		binFile.write( struct.pack('<f', normal) )
		
	#保存纹理坐标数量
	binFile.write( struct.pack('<I', len(UVCoord)) )
	print("UVCoord", len(UVCoord))
	#保存纹理坐标
	for uv in UVCoord:
		binFile.write( struct.pack('<f', uv) )
		
	#保存索引数量
	binFile.write( struct.pack('<I', len(VIndex)) )
	print("VIndex", len(VIndex))
	#保存索引
	for index in VIndex:
		binFile.write( index )

	return me

def f_保存网格顶点权重所在骨骼(binFile, me):
	binFile.write( struct.pack('I', len(me.vertices) ) )
	for vert in me.vertices:
		最大权重 = 0.0
		所在骨骼ID = 0
		for group in vert.groups:
			if group.weight >= 最大权重 :
				最大权重 = group.weight
				所在骨骼ID = group.group
		binFile.write( struct.pack('I', 所在骨骼ID ) )

def f_保存骨骼(binFile, bone, 名称组, 骨骼结构):
	名称组.append(bone.name)
	#骨骼结构.append(len(骨骼结构))

	binFile.write( struct.pack('<f', bone.tail.x ) )
	binFile.write( struct.pack('<f', bone.tail.z ) )
	binFile.write( struct.pack('<f', -bone.tail.y ) )
	
	if bone.parent != None:
		binFile.write( struct.pack('B', 1) )
		名称组.append(bone.parent.name)
	else:
		binFile.write( struct.pack('B', 0) )
		名称组.append("")
	骨骼结构.append(0)
	
	#保存子级
	骨骼结构.append(len(bone.children))
	binFile.write( struct.pack('<I', len(bone.children) ) )
	for children in bone.children :
		f_保存骨骼(binFile, children, 名称组, 骨骼结构)



def f_保存曲线物体(binFile, obj, scene):
	#保存边顶点数量
	binFile.write( struct.pack('B', len(obj.data.splines)) )
	for 线条 in obj.data.splines:
		binFile.write( struct.pack('B', len(线条.bezier_points)) )
		for vert in 线条.bezier_points:
			#保存顶点
			binFile.write( struct.pack('f', vert.co[0]) )
			binFile.write( struct.pack('f', vert.co[1]) )
			binFile.write( struct.pack('f', vert.co[2]) )





def f_Engne_ExportTree(ctx, path, selease):
	binFile = open(path, 'wb')
	#保存版本
	binFile.write( struct.pack('I', 1) )


	scene = bpy.context.scene
	树对象数量 = 0
	for obj in bpy.data.objects:
		if obj.type == 'ARMATURE' :
			if f_是否为树对象(obj, 'T_TreeBone') :
				树对象数量 += 1
	binFile.write( struct.pack('I', 树对象数量 ) )


	for obj in bpy.data.objects:
		if obj.type == 'ARMATURE' :
			if f_是否为树对象(obj, 'T_TreeBone') :
				f_SaveObjName(binFile, obj.name)
				#保存LOD层
				binFile.write( struct.pack('I', len(obj.lod_levels) ) )
				for lod in obj.lod_levels:
					#当前对象LOD层数量
					if f_是否为树对象(lod.object, 'T_TreeLeaves'):
						#保存树叶
						binFile.write( struct.pack('I', ENUM_树叶 ) )
						binFile.write( struct.pack('I', len(lod.object.lod_levels) ) )
						
						for 树叶lod in lod.object.lod_levels:
							me = f_保存网格物体(binFile, 树叶lod.object, scene)
							#保存顶点所在骨骼
							f_保存网格顶点权重所在骨骼(binFile, me)

					elif f_是否为树对象(lod.object, 'T_TreeTrunk'):
						binFile.write( struct.pack('I', ENUM_树干 ) )
						binFile.write( struct.pack('I', len(lod.object.lod_levels) ) )
						
						for 树干lod in lod.object.lod_levels:
							me = f_保存网格物体(binFile, 树干lod.object, scene)
							#保存顶点所在骨骼
							f_保存网格顶点权重所在骨骼(binFile, me)

					else:
						binFile.write( struct.pack('I', ENUM_树骨骼 ) )


				#保存骨骼
				骨骼名称 = []
				骨骼顶点 = []
				for bone in obj.data.bones :
					骨头方向 = bone.tail_local - bone.head_local
					骨骼顶点.append(骨头方向.x)
					骨骼顶点.append(骨头方向.z)
					骨骼顶点.append(-骨头方向.y)
					#父骨骼索引
					骨骼顶点.append(-1)
					
					if bone.parent != None:
						骨骼名称.append(bone.parent.name)
					else:
						骨骼名称.append("")
				
				for 父骨骼名称ID in range(0, len(骨骼名称) ) :
					父骨骼名称 = 骨骼名称[父骨骼名称ID]
					for boneID in range(0, len(obj.data.bones) ) :
						if obj.data.bones[boneID].name == 父骨骼名称 :
							#设置父骨骼索引
							骨骼顶点[父骨骼名称ID*4 + 3] = boneID
							break
				print("len(骨骼顶点) -- ", len(骨骼顶点))
				binFile.write( struct.pack('<I', len(骨骼顶点) ) )
				for bone in 骨骼顶点 :
					binFile.write( struct.pack('<f', bone ) )



				#binFile.write( struct.pack('I', 0 ) )
	#binFile.write( struct.pack('I', 0xffffffff ) )	
	
	

	





class Engine_ExportTree(bpy.types.Operator, ExportHelper):
	bl_idname = "export_scene.tree"
	bl_label = 'Export 树'
	bl_options = {'PRESET'}

	#filename_ext = StringProperty(subtype='FILE_PATH')
	filename_ext = '.mt'
	filepath = StringProperty(subtype='FILE_PATH')

	SelectOnly = BoolProperty(name="导出选定对象", description="导出选定对象", default=False)


	def execute(self, context):
		#self.filename_ext = "mbt.mm"
		#from.import export_obj
		#selectOnly = self.SelectOnly[1]['default']
		f_Engne_ExportTree(context, self.filepath, self.SelectOnly)
		#Engine_SaveModel(context, self.SelectOnly, self.filepath)
		return {'FINISHED'}
		#return export_obj.save(self, context, **keywords)


def menu_func_export(self, context):
	self.layout.operator(Engine_ExportTree.bl_idname, text="植被 (.mt)")


def register():
	bpy.utils.register_module(__name__)
	bpy.types.INFO_MT_file_export.append(menu_func_export)

def unregister():
	bpy.utils.unregister_module(__name__)
	bpy.types.INFO_MT_file_export.remove(menu_func_export)


if __name__ == "__main__":
	register()






